package com.apanal.qlife.sys.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.shiro.authz.permission.WildcardPermission;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.apanal.qlife.common.constants.Constants;
import com.apanal.qlife.common.page.Page;
import com.apanal.qlife.common.page.PageReturn;
import com.apanal.qlife.common.util.IdWorkerFactory;
import com.apanal.qlife.sys.dao.ResourceMapper;
import com.apanal.qlife.sys.model.Resource;
import com.apanal.qlife.sys.model.User;
import com.apanal.qlife.sys.service.ResourceService;

/**
 * 资源服务层接口实现类
 * 
 * @author shuliangxing
 * 
 * @date 2015-1-14上午11:36:08
 */
@Service
public class ResourceServiceImpl implements ResourceService {

	@Autowired
	private ResourceMapper mapper;

	@Override
	public String deleteById(Long id) {
		mapper.deleteChildRecursion(id);
		mapper.deleteByPrimaryKey(id);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public String insert(Resource record) {
		if (record.getResId() == null) {
			record.setResId(IdWorkerFactory.nextId());
		}
		mapper.insert(record);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public String insertSelective(Resource record) {
		if (record.getResId() == null) {
			record.setResId(IdWorkerFactory.nextId());
		}
		mapper.insertSelective(record);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public Resource selectById(Long id) {
		return mapper.selectByPrimaryKey(id);
	}

	@Override
	public String updateByIdSelective(Resource record) {
		// 1菜单 2按钮
		if (record.getResType() == 2) {
			// 清空菜单属性
			record.setResUrl("");
			record.setResOrder(0);
			record.setResClass("");
		}
		mapper.updateByPrimaryKeySelective(record);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public String updateById(Resource record) {
		mapper.updateByPrimaryKey(record);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public List<Resource> selectAll() {
		return mapper.select(null);
	}

	@Override
	public List<Resource> selectAllNormal() {
		Resource param = new Resource();
		param.setNormal(Constants.NORMAL_TRUE);
		return mapper.select(param);
	}

	@Override
	public PageReturn<Resource> selectForPage(Resource entity, Page page) {
		int count = mapper.selectForPageCount(entity, page);
		List<Resource> list = mapper.selectForPage(entity, page);
		return new PageReturn<Resource>(list, count, page, entity);
	}

	@Override
	public String deleteSoft(Long id, Long useId) {
		Resource entity = new Resource();
		entity.setResId(id);
		entity.setLastUpdateBy(useId);
		entity.setStatus(Constants.IS_VALID_FALSE);
		mapper.updateByPrimaryKeySelective(entity);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public Set<String> findPermissionsByUser(User user) {
		return mapper.findPermissionsByUserName(user.getUseName());
	}

	@Override
	public List<Resource> findMenus(Set<String> permissions) {
		List<Resource> allMenu = selectAllMenu();
		List<Resource> menus = new ArrayList<Resource>();
		for (Resource resource : allMenu) {
			// 排除停用菜单
			if (resource.getNormal() == 1) {
				if (!hasPermission(permissions, resource)) {
					continue;
				}
				menus.add(resource);
			}
		}

		Map<Long, Resource> map = resourceListToMap(allMenu);
		List<Resource> lostMenus = new ArrayList<Resource>();
		for (Resource m : menus) {
			// 如果资源层级大于2,且父资源为空时,添加父资源(一级菜单有权限字符串,二级菜单没有权限字符串的情况,要显示一二级菜单)
			if (m.getResLevel() > 2) {
				Resource parent = map.get(m.getResPId());
				// 排除停用菜单,如果上级菜单禁用,都不显示
				if (parent.getNormal() == 0) {
					continue;
				}
				if (!menus.contains(parent) && !lostMenus.contains(parent)) {
					lostMenus.add(parent);
				}
			}
		}

		menus.addAll(lostMenus);
		return menus;

	}

	@Override
	public Resource findMenusForLevel(Set<String> permissions) {
		List<Resource> menus = findMenus(permissions);
		return getResourceForLevel(menus);
	}

	@Override
	public Resource findMenusForLevel(User user) {
		ResourceService proxyResourceService = (ResourceService) AopContext
				.currentProxy();
		Set<String> permissions = proxyResourceService
				.findPermissionsByUser(user);
		List<Resource> menus = findMenus(permissions);
		return getResourceForLevel(menus);
	}

	@Override
	public List<Resource> selectAllMenu() {
		return mapper.selectAllMenu();
	}

	@Override
	public List<Resource> selectAllButton() {
		return mapper.selectAllButton();
	}

	@Override
	public Boolean checkResourceNameExist(Long resId, String resName) {
		Boolean result = false;
		Resource resource = new Resource();
		resource.setResName(resName);
		List<Resource> list = mapper.select(resource);

		// 资源id大于0,表示修改资源校验,排除当前资源
		if (resId > 0) {
			for (Resource r : list) {
				if (!r.getResId().equals(resId)) {
					result = true;
					break;
				}
			}
		}
		// 表示新增资源校验
		else {
			result = !list.isEmpty();
		}
		return result;
	}

	/**
	 * 权限集合是否有权限访问资源
	 * 
	 * @param permissions
	 * @param resource
	 * @return
	 */
	private boolean hasPermission(Set<String> permissions, Resource resource) {
		if (StringUtils.isEmpty(resource.getResPermission())) {
			return true;
		}
		// 返回根目录,方便封装菜单层级
		if (resource.getResLevel() == 1) {
			return true;
		}

		for (String permission : permissions) {
			WildcardPermission p1 = new WildcardPermission(permission);
			WildcardPermission p2 = new WildcardPermission(
					resource.getResPermission());
			if (p1.implies(p2) || p2.implies(p1)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 将资源按照层级封装
	 * 
	 * @param menus
	 * @return
	 */
	private Resource getResourceForLevel(List<Resource> menus) {
		// 资源一层为资源根目录,二层为一级菜单,三层为二级菜单,四层为按钮
		Resource root = new Resource();
		for (Resource r : menus) {
			if (r.getResLevel() == 1) {
				root = r;
				// 二层资源(一级菜单)集合
				List<Resource> firstMenuList = new ArrayList<Resource>();
				// 菜的分层封装
				for (Resource firstMenu : menus) {
					if (firstMenu.getResPId().equals(root.getResId())) {
						// 三层资源(二级菜单)集合
						List<Resource> secondMenuList = new ArrayList<Resource>();
						for (Resource secondMenu : menus) {
							if (secondMenu.getResPId().equals(
									firstMenu.getResId())) {
								// 四层资源(按钮)集合
								List<Resource> childButtonList = new ArrayList<Resource>();
								for (Resource button : menus) {
									if (button.getResPId().equals(
											secondMenu.getResId())) {
										childButtonList.add(button);
									}
								}
								secondMenu.setChildResList(childButtonList);
								secondMenuList.add(secondMenu);
							}
						}
						firstMenu.setChildResList(secondMenuList);
						firstMenuList.add(firstMenu);
					}
				}
				root.setChildResList(firstMenuList);
			}
		}
		return root;
	}

	@Override
	public String updateToEnableOrDisable(Resource resource) {
		resource.setNormal(resource.getNormal() == Constants.IS_VALID_TRUE ? Constants.IS_VALID_FALSE
				: Constants.IS_VALID_TRUE);
		mapper.updateByPrimaryKeySelective(resource);
		return Constants.DEFAULT_MSG_SUCCESS;
	}

	@Override
	public List<Resource> selectByRolId(Long rolId) {
		return mapper.selectByRoleId(rolId);
	}

	@Override
	public List<Resource> selectByGroId(Long groId) {
		return mapper.selectByGroId(groId);
	}

	@Override
	public List<Resource> selectResourceAuthTree() {
		List<Resource> list = this.selectAll();
		List<Resource> emptyList = new ArrayList<Resource>();

		// 移除权限为空的节点
		for (Resource resource : list) {
			if (StringUtils.isEmpty(resource.getResPermission())) {
				emptyList.add(resource);
			}
		}

		list.removeAll(emptyList);
		return list;
	}

	/**
	 * 资源List转换Map,key:id value:资源
	 * 
	 * @param list
	 * @return
	 */
	private Map<Long, Resource> resourceListToMap(List<Resource> list) {
		Map<Long, Resource> map = new HashMap<Long, Resource>();
		for (Resource resource : list) {
			map.put(resource.getResId(), resource);
		}
		return map;
	}

}
